package com.chwl.framework.springboot.grpc;


import com.chwl.framework.grpc.ServerContext;
import com.chwl.framework.grpc.annotation.GrpcService;
import com.chwl.framework.grpc.discover.ServiceDiscoverService;
import com.chwl.framework.grpc.exception.ConnectionException;
import com.chwl.framework.grpc.exception.NotFoundException;
import com.chwl.framework.grpc.service.GrpcRequest;
import com.chwl.framework.springboot.grpc.service.UserDefinedInvocationHandler;
import io.grpc.StatusRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;

public class GrpcServiceProxy<T> implements InvocationHandler {
    private Logger logger = LoggerFactory.getLogger(GrpcServiceProxy.class);

    private Class<T> grpcService;
    UserDefinedInvocationHandler userDefinedInvocationHandler;
    DefaultListableBeanFactory factory;

    public GrpcServiceProxy(Class<T> grpcService, UserDefinedInvocationHandler handler, DefaultListableBeanFactory defaultListableBeanFactory) {
        this.grpcService = grpcService;
        this.userDefinedInvocationHandler = handler;
        this.factory = defaultListableBeanFactory;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        GrpcService annotation = grpcService.getAnnotation(GrpcService.class);
        String server = annotation.server();

        String className = grpcService.getSimpleName();
        String beanName = annotation.bean();
        if (StringUtils.isEmpty(beanName)) {
            beanName = Character.toLowerCase(className.charAt(0)) + className.substring(1);
        }
        if (userDefinedInvocationHandler != null) {
            Object object = userDefinedInvocationHandler.invoke(factory, beanName, method.getName(), args);
            if (object != null) {
                return object;
            }
        }
        GrpcRequest request = new GrpcRequest();
        request.setBeanName(beanName);
        request.setMethodName(method.getName());
        request.setArgs(args);
        ServerContext context = null;
        try {
            context = ServiceDiscoverService.getInstance().findServer(server);// GrpcClient.connect(server);
            //暂支持单个服务器请求
            return context.handle(request).getResult();
        } catch (NotFoundException e) {
            logger.error("invoke grpc service fail,serviceName:{},error message:{}", server, e.getMessage(), e);
            throw e;
        } catch (ConnectionException | StatusRuntimeException e) {
            logger.error("invoke grpc service fail,server:{},error message:{}", context.getIp() + ":" + context.getPort(), e.getMessage(), e);
            return invoke(proxy, method, args);
        } catch (Exception e) {
            throw e;
        }
    }

}
